package dao

import (
	"context"
	"errors"
	"ldaccount/internal/object"
	"ldaccount/pkg/db/pgex"
	"ldaccount/pkg/util"
	"time"

	"ldaccount/internal/model"
)

type AccountsRepo interface {
	// CreateAccounts 批量创建账号
	CreateAccounts(ctx context.Context, accs []*model.Accounts) (int64, error)
	// CreateAccount 创建账号
	CreateAccount(ctx context.Context, acc *model.Accounts) (int64, error)
	// GetAccountByMobile 根据手机号获取账号
	GetAccountByMobile(ctx context.Context, mobile string) (*model.Accounts, error)
	// GetAccountByEmail 根据邮箱获取账号
	GetAccountByEmail(ctx context.Context, email string) (*model.Accounts, error)
	// GetAccountByGID 根据 gid 获取账号信息
	GetAccountByGID(ctx context.Context, gID string) (*model.Accounts, error)
	// GetAccountById 根据 id 获取账号信息
	GetAccountById(ctx context.Context, id int64) (*model.Accounts, error)
	// GetAccountByChannel 根据 email origin  获取账号信息
	GetAccountByChannel(ctx context.Context, email, origin string) (*model.Accounts, error)
	// UpdateAccount 更新账号
	UpdateAccount(ctx context.Context, acc *model.Accounts) error
	// SetMobile 更新账号手机
	SetMobile(ctx context.Context, acc *model.Accounts) error
	// ResetPassword 更新账号密码
	ResetPassword(ctx context.Context, acc *model.Accounts) error
	// CachePlatformUser 缓存平台用户信息
	CachePlatformUser(ctx context.Context, ticket string, info *object.PlatformUserInfo) error
	// GetPlatformUser 获取平台用户信息
	GetPlatformUser(ctx context.Context, reqId string) (*object.PlatformUserInfo, error)
	// UpdateAccountStatus 更新账号状态
	UpdateAccountStatus(ctx context.Context, acc *model.Accounts) error
}

type accDaoImpl struct {
	*Dao
	name string
}

var accRepo AccountsRepo

// GetAccountsRepo return accoutns repo
func GetAccountsRepo() AccountsRepo {
	return accRepo
}

// InitAccountsRepo injects AccountsRepo with implementation
func InitAccountsRepo(a AccountsRepo) {
	accRepo = a
}

// NewAccountsRepo initialize
func NewAccountsRepo() *accDaoImpl {
	return &accDaoImpl{
		Dao:  dao,
		name: "dao_accounts",
	}
}

// CreateAccounts 创建账号
func (a *accDaoImpl) CreateAccounts(ctx context.Context, accs []*model.Accounts) (int64, error) {
	if len(accs) < 1 {
		return 0, nil
	}
	var params [][]interface{}
	for _, acc := range accs {
		if acc.Status != 0 {
			acc.Status = model.AccountsOk
		}
		if acc.CreatedAt.IsZero() {
			acc.CreatedAt = util.GetNow()
			acc.UpdatedAt = acc.CreatedAt
		}
		val := []interface{}{
			acc.GID,
			acc.Mobile,
			acc.Email,
			acc.Status,
			acc.Password,
			acc.UserName,
			acc.CountryCode,
			acc.Origin,
			acc.CreatedAt,
			acc.UpdatedAt,
		}
		params = append(params, val)
	}

	query := "INSERT INTO accounts (g_id, mobile, email, status, password, user_name, country_code, " +
		"origin, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

	aff, err := a.db.InsertMany(ctx, query, params)
	if err != nil {
		return 0, err
	}
	rowNum, _ := aff.GetRowsAffected()
	return rowNum, nil
}

// CreateAccount 创建账号
func (a *accDaoImpl) CreateAccount(ctx context.Context, acc *model.Accounts) (int64, error) {
	if acc == nil {
		return 0, nil
	}
	param := []interface{}{
		acc.GID,
		acc.Mobile,
		acc.Email,
		acc.Status,
		acc.Password,
		acc.UserName,
		acc.Avatar,
		acc.CountryCode,
		acc.Origin,
		acc.CreatedAt,
		acc.UpdatedAt,
	}

	query := "INSERT INTO accounts (g_id, mobile, email, status, password, user_name, avatar, country_code, " +
		"origin, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

	aff, err := a.db.PgExec(ctx, "id", query, param...)
	if err != nil {
		return 0, err
	}
	lastId, _ := aff.GetLastId()
	return lastId, nil
}

// GetAccountByMobile 根据手机号获取账号
func (a *accDaoImpl) GetAccountByMobile(ctx context.Context, mobile string) (*model.Accounts, error) {
	if mobile == "" {
		return nil, nil
	}
	query := "SELECT * FROM accounts WHERE  mobile=? AND deleted_at=0"
	var accs []*model.Accounts
	err := a.db.Query(ctx, &accs, query, mobile)
	if err != nil {
		return nil, nil
	}
	if len(accs) == 0 {
		return nil, nil
	}
	return accs[0], err
}

// GetAccountByEmail 根据邮箱获取账号
func (a *accDaoImpl) GetAccountByEmail(ctx context.Context, email string) (*model.Accounts, error) {
	if email == "" {
		return nil, nil
	}
	query := "SELECT * FROM accounts WHERE email=? AND deleted_at=0"
	acc := &model.Accounts{}
	err := a.db.Get(ctx, acc, query, email)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// GetAccountByGID 根据 gid 获取账号信息
func (a *accDaoImpl) GetAccountByGID(ctx context.Context, gID string) (*model.Accounts, error) {
	if gID == "" {
		return nil, nil
	}
	query := "SELECT * FROM accounts WHERE g_id=? AND deleted_at=0"
	acc := &model.Accounts{}
	err := a.db.Get(ctx, acc, query, gID)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// GetAccountById 根据 id 获取账号信息
func (a *accDaoImpl) GetAccountById(ctx context.Context, id int64) (*model.Accounts, error) {
	if id == 0 {
		return nil, nil
	}
	query := "SELECT * FROM accounts WHERE id=? AND deleted_at=0"
	acc := &model.Accounts{}
	err := a.db.Get(ctx, acc, query, id)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// GetAccountByChannel 根据 platform email  获取账号信息
func (a *accDaoImpl) GetAccountByChannel(ctx context.Context, email, origin string) (*model.Accounts, error) {
	if email == "" || origin == "" {
		return nil, nil
	}

	query := "SELECT * FROM accounts WHERE email=? AND origin=? AND deleted_at=0"
	acc := &model.Accounts{}
	err := a.db.Get(ctx, acc, query, email, origin)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// UpdateAccount 更新账号
func (a *accDaoImpl) UpdateAccount(ctx context.Context, acc *model.Accounts) error {
	if acc == nil {
		return nil
	}
	acc.UpdatedAt = util.GetNow()
	param := []interface{}{
		acc.Mobile,
		acc.Email,
		acc.Status,
		acc.UserName,
		acc.CountryCode,
		acc.Avatar,
		acc.UpdatedAt,
		acc.ID,
	}
	query := "UPDATE accounts SET mobile=?, email=?, status=?, user_name=?, country_code=?, avatar=?, updated_at=? " +
		"WHERE id=? AND deleted_at=0"
	_, err := a.db.Update(ctx, query, param...)
	return err
}

// UpdateAccountStatus 更新账号状态
func (a *accDaoImpl) UpdateAccountStatus(ctx context.Context, acc *model.Accounts) error {
	if acc == nil {
		return nil
	}
	acc.UpdatedAt = util.GetNow()
	param := []interface{}{
		acc.Status,
		acc.UpdatedAt,
		acc.ID,
	}
	query := "UPDATE accounts SET status=?, updated_at=? WHERE id=? AND deleted_at=0"
	_, err := a.db.Update(ctx, query, param...)
	return err
}

// SetMobile 更新账号手机
func (a *accDaoImpl) SetMobile(ctx context.Context, acc *model.Accounts) error {
	if acc == nil {
		return nil
	}
	acc.UpdatedAt = util.GetNow()
	query := "UPDATE accounts SET mobile=?, updated_at=? WHERE id=? AND deleted_at=0"
	_, err := a.db.Update(ctx, query, acc.Mobile, acc.UpdatedAt, acc.ID)
	return err
}

// ResetPassword 更新账号密码
func (a *accDaoImpl) ResetPassword(ctx context.Context, acc *model.Accounts) error {
	if acc == nil {
		return nil
	}
	acc.UpdatedAt = util.GetNow()
	query := "UPDATE accounts SET password=?, updated_at=? WHERE id=? AND deleted_at=0"
	_, err := a.db.Update(ctx, query, acc.Password, acc.UpdatedAt, acc.ID)
	return err
}

// CachePlatformUser 缓存平台用户信息
func (a *accDaoImpl) CachePlatformUser(ctx context.Context, ticket string, info *object.PlatformUserInfo) error {
	if info == nil {
		return nil
	}
	infoB, err := json.Marshal(info)
	if err != nil {
		return err
	}
	key := a.BuildCacheKey("platform_user", ticket)
	_, err = a.cache.Set(ctx, key, infoB, 20*time.Minute)
	return err
}

// GetPlatformUser 获取平台用户信息
func (a *accDaoImpl) GetPlatformUser(ctx context.Context, ticket string) (*object.PlatformUserInfo, error) {
	key := a.BuildCacheKey("platform_user", ticket)
	r, err := a.cache.Get(ctx, key)
	if err != nil {
		if isNil(err) {
			return nil, nil
		}
		return nil, err
	}
	info := &object.PlatformUserInfo{}
	err = json.Unmarshal([]byte(r), info)
	return info, err
}
